package cc.risingsun.wing.core.generator;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cc.risingsun.wing.annotations.Select;
import cc.risingsun.wing.apache.dbutils.QueryRunner;
import cc.risingsun.wing.apache.dbutils.ResultSetHandler;
import cc.risingsun.wing.apache.dbutils.handlers.BeanHandler;
import cc.risingsun.wing.apache.dbutils.handlers.BeanListHandler;
import cc.risingsun.wing.core.WingClass;
import cc.risingsun.wing.core.WingMethod;
import cc.risingsun.wing.core.scanner.ScannerSkipException;
import cc.risingsun.wing.core.scanner.ScannerSkipException.SkipCode;
import cc.risingsun.wing.dai.SQLRepository;

/**
 * SQL 访问数据处理器
 * 
 * @author iron.yin@gmail.com
 * @sina 2012-8-27
 */

public class SQLGenerator implements WingTypeGenerator {

	private final Logger logger = LoggerFactory.getLogger(SQLGenerator.class);
	
	private final String SUPER_CLASS = Type.getInternalName(SQLRepository.class);
	private final String BEAN_HANDLER = Type.getInternalName(BeanHandler.class);
	private final String BEAN_LIST_HANDLER = Type.getInternalName(BeanListHandler.class);
	private final Type QUERY = Type.getType(QueryRunner.class);
	
	private final String QUERY_METHOD_NAME="query";
	
	private String QUERY_METHOD;
	{
			try {
				QUERY_METHOD = Type.getMethodDescriptor(QueryRunner.class.getMethod(QUERY_METHOD_NAME, String.class, ResultSetHandler.class, Object[].class));
			} catch (NoSuchMethodException e) {
				logger.error(e.getMessage(),e);
			}
	}
	private final ClassWriter cw;
	private MethodVisitor mv;

	public SQLGenerator() {
		cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
	}

	@Override
	public void checkType(int access, String annoName, String resourceName) {
		if ((access & ACC_INTERFACE) == 0) {
			throw new ScannerSkipException(SkipCode.NONINTERFACE, annoName, resourceName);
		}
	}

	@Override
	public void constructor(WingClass clazz) {
		cw.visit(JDK_VER, ACC_PUBLIC, clazz.getInternalName(), null, SUPER_CLASS, clazz.getInterfaces());
		mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
		mv.visitCode();
		mv.visitVarInsn(ALOAD, 0);
		mv.visitMethodInsn(INVOKESPECIAL, SUPER_CLASS, "<init>", "()V");
		mv.visitInsn(RETURN);
		mv.visitMaxs(0, 0);
		mv.visitEnd();
	}

	@Override
	public void generateMethod(WingMethod method) {
		// 构造方法的名称,参数,异常和返回
		final Type returnType = method.getReturnType();
		mv = cw.visitMethod(ACC_PUBLIC, method.getName(), method.getDesc(), null, method.getExceptions());
		mv.visitCode();
		mv.visitVarInsn(ALOAD, 0);
		// 获取父类的query(QueryRunner)成员
		mv.visitFieldInsn(GETFIELD, SUPER_CLASS, QUERY_METHOD_NAME, QUERY.getDescriptor());
		//根据该方法的标注获取对应的SQL方法
		String sql = method.getAnnotaion(Select.class).get("value").toString();
		mv.visitLdcInsn(sql);
		
		mv.visitTypeInsn(NEW, BEAN_HANDLER);
		mv.visitInsn(DUP);
		//如果返回类型是一个List,则需要从列表中
		mv.visitLdcInsn(returnType);
		mv.visitMethodInsn(INVOKESPECIAL, BEAN_HANDLER, "<init>", "(Ljava/lang/Class;)V");
		mv.visitInsn(ICONST_1);
		mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
		mv.visitInsn(DUP);
		mv.visitInsn(ICONST_0);
		mv.visitVarInsn(ALOAD, 1);
		mv.visitInsn(AASTORE);
		mv.visitMethodInsn(INVOKEVIRTUAL, QUERY.getInternalName(), QUERY_METHOD_NAME, QUERY_METHOD);
		mv.visitTypeInsn(CHECKCAST, returnType.getInternalName());
		mv.visitInsn(ARETURN);
		mv.visitMaxs(0, 0);
		mv.visitEnd();
	}
	
	public byte[] toByte() {
		cw.visitEnd();
		return cw.toByteArray();
	}
}
